﻿using ldhWebApiWF.database;
using ldhWebApiWF.models;
using MongoDB.Bson;
using MongoDB.Driver;
using MongoDB.Driver.Linq;
using System;
using System.Linq;
using System.Collections.Generic;
using System.IO;
using System.Net;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Threading.Tasks;
using System.Web.Http;
using System.Web.Http.Cors;
using System.Web.Http.Description;
using Microsoft.AspNet.SignalR;

namespace ldhWebApiWF.Controller
{
    // Allow CORS for all origins. (Caution!)
    //[EnableCors(origins: "*", headers: "*", methods: "*")]
    //[EnableCors(origins: "http://www.contoso.com,http://www.example.com", headers: "accept,content-type,origin,x-my-header", methods: "get,post")]
    //[AuthUkey]
    //[BasicAuthenticationFilter]
    [RoutePrefix("api")]
    public class BooksController : ApiController
    {
        IMongoCollection<Book> books;

        public BooksController()
        {
            books = BaseManager.GetClient<Book>("Bookdb", "Books");
            books.Indexes.CreateOneAsync(Builders<Book>.IndexKeys.Ascending(x => x.ReleaseDate));
            //using (var cursor = await books.Indexes.ListAsync())
            //{
            //    var indexes = await cursor.ToListAsync();
            //}
        }

        //customer api
        [HttpPost]
        [Route("customers/{customerId}/orders/{orderId}")]
        public string GetOrderByCustomer([FromBody]string data, int customerId, int orderId) 
        {
            //invoke myhub clients for signalr
            //var context = GlobalHost.ConnectionManager.GetHubContext<MyHub>();

            BsonDocument bd=new BsonDocument();
            bd.AddRange(new BsonDocument("a", customerId));
            bd.AddRange(new BsonDocument("b", orderId));
            return bd.ToJson();
        }

        [HttpPost]
        [Route("file/upload")]
        public async Task<IHttpActionResult> UploadFile()
        {
            if (!Request.Content.IsMimeMultipartContent())
            {
                return StatusCode(HttpStatusCode.UnsupportedMediaType);
            }

            var path = AppDomain.CurrentDomain.BaseDirectory + "uploads\\";
            if (!Directory.Exists(path))
            {
                Directory.CreateDirectory(path);
            }
            var provider = new MultipartFormStreamProvider(path);
            try
            {
                await Request.Content.ReadAsMultipartAsync(provider);
                if (provider.FileData.Count == 0)
                {
                    ModelState.AddModelError(Guid.NewGuid().ToString(), "服务器不支持的文件类型");
                    return BadRequest(ModelState);
                }
                foreach (MultipartFileData fileData in provider.FileData)
                {
                    var fileName = Extens.TakeFileName(fileData.Headers.ContentDisposition.FileName);
                    if (string.IsNullOrEmpty(fileName))
                    {
                        File.Delete(fileData.LocalFileName);
                        ModelState.AddModelError(Guid.NewGuid().ToString(), "文件名不能空");
                        return BadRequest(ModelState);
                    }
                    if (Path.GetInvalidFileNameChars().Where(x => fileName.Contains(x)).Any())
                    {
                        File.Delete(fileData.LocalFileName);
                        ModelState.AddModelError(Guid.NewGuid().ToString(), "文件名中含有非法字符");
                        return BadRequest(ModelState);
                    }
                    ////不允许同名文件上传
                    if (File.Exists(path + fileName))
                    {
                        File.Delete(fileData.LocalFileName);
                        ModelState.AddModelError(Guid.NewGuid().ToString(), "该文件已存在于服务器");
                        return BadRequest(ModelState);
                    }
                    //////允许同名文件上传,替换服务器同文件
                    //if (File.Exists(path + fileName))
                    //{
                    //    File.Delete(path + fileName);
                    //}
                    //把缓存文件移动至正式文件夹
                    File.Move(fileData.LocalFileName, path + fileName);
                }
            }
            catch (Exception e)
            {
                ModelState.AddModelError(Guid.NewGuid().ToString(), e.Message);
                return BadRequest(ModelState);
            }
            return Ok();
        }

        //文件下载改用文件服务器端口下载
        //代码位于Form1服务启动代码

        //[ActionName("DefaultAction")] //Map Action and you can name your method with any text
        // GET api/books
        //[DeflateCompression]//using zlib compression
        [Route("books")]
        public async Task<IHttpActionResult> GetBooks()
        {
            //禁止使用decimal，转用double型
            //var names = await books
            //    .Find(x => x.Price >50 && x.Price <300)
            //    .ToListAsync();
            //return Ok(names);

            //v2.1
            //var names = books.AsQueryable().Where(x => x.Price >= 200 && x.Price <= 300);

            //int pageSize = 500;
            //var totalRecord = await books.CountAsync(new BsonDocument());
            //var totalPage = (totalRecord + pageSize - 1) / pageSize;
            ////2.0
            ////var names = await books.Find(new BsonDocument()).Skip((int)totalPage).Limit(50).ToListAsync();
            ////2.1
            //var names = books.AsQueryable().Skip((int)totalPage * 0).Take(pageSize);

            //日期时间操作提交时必须是utc时间
            //日期时间查询时必须先转为本地时间
            //var start = DateTime.Parse("2015-10-17T11:11:29").ToLocalTime();
            //var end = DateTime.Parse("2015-10-17T12:12:20").ToLocalTime();
            ////2.1
            //var names = await books.Find(b => b.ReleaseDate >= start && b.ReleaseDate <= end).ToListAsync();

            //return Ok(names);

            var bks = await books.Find(new BsonDocument()).ToListAsync();
            return Ok(bks);
        }

        //// GET api/books/5
        [Route("books/{id}")]
        //[ResponseType(typeof(Book))]
        public async Task<IHttpActionResult> GetBook(string id)
        {
            //身份验证
            //var pwd = Request.Headers.SingleOrDefault(h => h.Key == "pwd");
            //if (pwd.Value.FirstOrDefault() != "123")
            //{
            //    return StatusCode(HttpStatusCode.NotFound);
            //}

            ObjectId oid;
            if (!ObjectId.TryParse(id, out oid))
            {
                return StatusCode(HttpStatusCode.BadRequest);
            }
            var book = await books.Find(new BsonDocument("_id",oid)).FirstOrDefaultAsync();
            if (book == null)
            {
                return NotFound();
            }

            //return Ok(book);
            return Ok(book.ToJson());
        }

        // PUT api/books/5
        [Route("books/{id}")]
        [HttpPut]
        public async Task<IHttpActionResult> PutBook(string id, Book book)
        {
            if (!ModelState.IsValid)
            {
                return BadRequest(ModelState);
            }

            if (!await BookExists(id))
            {
                return NotFound();
            }

            //var result = await books.FindOneAndUpdateAsync(x=>x.Id == ObjectId.Parse(id), Builders<Book>.Update.Set(x => x.Price, book.Price));
            var dbbook = await books.Find(x => x.Id == ObjectId.Parse(id)).SingleAsync();
            dbbook.Genre = book.Genre;
            dbbook.Price = book.Price;
            dbbook.Title = book.Title;
            var result = await books.ReplaceOneAsync(x => x.Id == ObjectId.Parse(id), dbbook);
            return StatusCode(HttpStatusCode.NoContent);
        }

        //// POST api/BookApi
        //[ActionName("DefaultAction")]
        [Route("books")]
        [HttpPost]
        [ResponseType(typeof(Book))]
        public async Task<IHttpActionResult> PostBook(Book book)
        {
            if (!ModelState.IsValid)
            {
                return BadRequest(ModelState);
            }
            //时区+8
            //book.ReleaseDate = book.ReleaseDate.AddHours(8);
            //Stopwatch sw = Stopwatch.StartNew();
            await books.InsertOneAsync(book);
            //Console.WriteLine(sw.ElapsedMilliseconds);

            //List<Book> bks = new List<Book>();
            //for (int i = 0; i < 20; i++)
            //{
            //    bks.Add(new Book() { Title = "Gizmo", Price = 300, Genre = "Widget", ReleaseDate = DateTime.Now, staute = em_staute.好, author = new Author() { Name = "jacob" } });
            //}
            //Stopwatch sw = Stopwatch.StartNew();
            //await books.InsertManyAsync(bks);
            //Console.WriteLine(sw.ElapsedMilliseconds);
            return Ok(book);
        }

        // DELETE api/BookApi/5
        [Route("books/{id}")]
        [HttpDelete]
        [ResponseType(typeof(Book))]
        public async Task<IHttpActionResult> DeleteBook(string id)
        {
            if (!await BookExists(id))
            {
                return NotFound();
            }

            var result = await books.DeleteOneAsync(x => x.Id == ObjectId.Parse(id));

            return Ok(result);
        }

        protected override void Dispose(bool disposing)
        {
            base.Dispose(disposing);
        }

        private async Task<bool> BookExists(string id)
        {
            ObjectId outId;
            if (ObjectId.TryParse(id, out outId))
            {
                if (await books.CountAsync(x => x.Id == outId) > 0)
                {
                    return true;
                }
            }
            return false;
        }
    }
}
